package wiiusej.apptest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import wiiusej.*;
import wiiusej.apptest.activityTasks.ComClient;
import wiiusej.apptest.activityTasks.EnergyTransmisionTask;

import wiiusej.apptest.activityTasks.RealTimeFeedback;
import wiiusej.apptest.activityTasks.Spell;
import wiiusej.apptest.activityTasks.SpellGameTask;
import wiiusej.apptest.generalTasks.ActivateSpeaker;
import wiiusej.apptest.generalTasks.ActiveSound;
import wiiusej.apptest.generalTasks.EnableMotionTask;
import wiiusej.apptest.generalTasks.OnMotionSensingTask;
import wiiusej.apptest.generalTasks.VolumeSpeakerTask;
import wiiusej.apptest.softwareControllers.SoftwareController;
import wiiusej.apptest.softwareControllers.SoftwareControllerImpl;
import wiiusej.apptest.statistics.AccelerationPaquet;
import wiiusej.apptest.statistics.AccelerationPaquetList;
import wiiusej.apptest.statistics.PacketManager;
import wiiusej.apptest.statistics.PacketWraped;
import wiiusej.hardwareControllers.HardwareManagerImpl;
import wiiusej.hardwareControllers.PermanenSoundController;
import wiiusej.hardwareControllers.PermanentController;
import wiiusej.hardwareControllers.PermanentLEDContoller;
import wiiusej.hardwareControllers.PermanentRumbleController;

import wiiusej.values.RawAcceleration;
import wiiusej.wiiusejevents.physicalevents.ExpansionEvent;
import wiiusej.wiiusejevents.physicalevents.IREvent;
import wiiusej.wiiusejevents.physicalevents.MotionSensingEvent;
import wiiusej.wiiusejevents.physicalevents.WiimoteButtonsEvent;
import wiiusej.wiiusejevents.utils.WiimoteBasicListener;
import wiiusej.wiiusejevents.utils.WiimoteListener;
import wiiusej.wiiusejevents.wiiuseapievents.ClassicControllerInsertedEvent;
import wiiusej.wiiusejevents.wiiuseapievents.ClassicControllerRemovedEvent;
import wiiusej.wiiusejevents.wiiuseapievents.DisconnectionEvent;
import wiiusej.wiiusejevents.wiiuseapievents.GuitarHeroInsertedEvent;
import wiiusej.wiiusejevents.wiiuseapievents.GuitarHeroRemovedEvent;
import wiiusej.wiiusejevents.wiiuseapievents.NunchukInsertedEvent;
import wiiusej.wiiusejevents.wiiuseapievents.NunchukRemovedEvent;
import wiiusej.wiiusejevents.wiiuseapievents.StatusEvent;
import wiiusej.wiiusejevents.wiiuseapievents.WiimoteEvent;

import org.apache.log4j.Category;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.spi.RootLogger;


public class WiimoteEventListener implements WiimoteBasicListener{
	
	
	//Logger
	static Logger fileLogger;
	
	//Logger URL
	private static final String fileURL = "src/test/java/wiiusej/resources/logs/tasks/WiimoteListener";
	
	//Machine States
	private AtomicBoolean speakerStatus = new AtomicBoolean(false);
	private AtomicBoolean rumbleStatus = new AtomicBoolean(true);
	
	Boolean motionButtonState = false;
	Integer captures = 0;
	
	//Concurrent Main Class
	protected static ExecutorService exe;
	
	//Wiimote object representation
	private Wiimote wiimote;
	
	//Energy Controller
	private AtomicInteger energyCharged = new AtomicInteger();
	
	List<AccelerationPaquet> eventList
    	= Collections.synchronizedList(new ArrayList<AccelerationPaquet>());
	
	
	private PacketWraped myPackets;
	
	Vector<AccelerationPaquet> myEventVector;
	
	protected long randomID;
	
	AccelerationPaquetList accPacketList;
	
	private BlockingQueue<Vector<AccelerationPaquet>> realTimeQueue 
		= new LinkedBlockingDeque<Vector<AccelerationPaquet>>();
	
	
	private BlockingQueue<Integer> gameToEnergy = new LinkedBlockingDeque<Integer>();
	private BlockingQueue<Integer> realTimeToGameController = new LinkedBlockingDeque<Integer>();
	
	private BlockingQueue<Spell> eneergyToComClient;
	
	private BlockingQueue<Integer> toRumbleQ = 
		new LinkedBlockingQueue<Integer>();
	
	private BlockingQueue<Integer> fromRealToSoundQ = 
		new LinkedBlockingQueue<Integer>();

	private BlockingQueue<Integer> toLEDQ = 
		new LinkedBlockingQueue<Integer>();
	
	
	private ConcurrentLinkedQueue<Integer> fromEnergyToGameQ = 
		new ConcurrentLinkedQueue<Integer>();
	
	
	private static final int NTHREADS = 100;	
	private static final ExecutorService executor = 
		Executors.newFixedThreadPool(NTHREADS);	
	
	private HardwareManagerImpl hardwareManager; 
		
		
		
		
	public WiimoteEventListener(Wiimote wiimote, ExecutorService exe, 
			ConcurrentLinkedQueue<AccelerationPaquetList> syncQueue, BlockingQueue<Spell> eneergyToComClient) {
		
		super();		
					
		this.eneergyToComClient = eneergyToComClient;
		this.wiimote = wiimote;
		this.exe = exe;
		
		accPacketList = new AccelerationPaquetList(wiimote.getId());				
		myPackets = new PacketWraped(accPacketList); 
		
		/*
		PropertyConfigurator.configure("log4j.properties");
		fileLogger = Logger.getLogger("speaker");*/
		
		Random random = new Random(System.currentTimeMillis());
		this.randomID = random.nextLong();
		
		
		
		PropertyConfigurator.configure("log4j.properties");
		this.fileLogger = Logger.getLogger("wiimoteListener");
		
		PatternLayout pattern = 
			new PatternLayout("%r %-5p %c %x - %m%n");		
		
		
		//register this listener in the Wiimote's listener list
		registerListeners();	
		
		//Speaker, rumbler and LED controllers
		initHardwareControllers();
		
		//System and Game Controllers
		initSoftwareComponents();
		
		//Turn on the acceleration packets capture
		activateMotionSensing();
		
	}	
	
	private void initHardwareControllers(){		
		hardwareManager = new HardwareManagerImpl(wiimote, fromRealToSoundQ, toRumbleQ, toLEDQ);
		executor.execute(hardwareManager);		
	}
	
	
	private void initSoftwareComponents(){	
		SoftwareController gameManager = new SoftwareControllerImpl(wiimote, realTimeQueue, realTimeToGameController, fromRealToSoundQ, gameToEnergy, 
				toRumbleQ, fromEnergyToGameQ, eneergyToComClient, toLEDQ);		
		
	}	
	
	private void registerListeners() {
		//We have to add our listener to the wiimote object
		System.out.println("Wiimote Listener - Registering in Wiimote List");
		wiimote.addWiiMoteEventListeners(this);		
	}
	
	private void activateMotionSensing() {
		wiimote.activateMotionSensing();		
	}

	private void getStatistics(MotionSensingEvent arg0){
		
		Future future = 
			exe.submit(new PacketManager(arg0, wiimote.getId(), randomID, myPackets));	
		
		try {
			//eventList = (List<AccelerationPaquet>) future1.get();
			//accPacketList.setPackets((Vector<AccelerationPaquet>) future.get());
			myPackets = (PacketWraped) future.get();
			
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		} catch (ExecutionException e1) {
			e1.printStackTrace();
		}		
	}
	
	private void realTimeApp(MotionSensingEvent arg0){
		try {
			realTimeQueue.put(myPackets.getMyEventVector().getPackets());
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}	
	
	/***********************************************************
	//WIIMOTE LISTENER INTERFACE 
	************************************************************/
	
	//Button Listener - will act as a State Machine
	public void onButtonsEvent(WiimoteButtonsEvent arg0) {
	        
	    //ENABLE MOTION CAPTURING
	    if (arg0.isButtonAJustPressed()){	    	
	    	try {
				gameToEnergy.put(0);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}	    	
	    }	    
	}
	
	//Motion Sensing Listener - depends on the state will capture motion measurements
	public void onMotionSensingEvent(MotionSensingEvent arg0) {		
		
		fileLogger.info("EventReceived - Wiimote: " + arg0.getWiimoteId() +
				" Packet: " + arg0.getRefNumber() +
				" Time: " + arg0.getTime());		
		
		fileLogger.info(" ");
		
		getStatistics(arg0);
		
		//syncQueue.offer(accPacketList);
		
		realTimeApp(arg0);		
    }	
	
	@Override
	public void onDisconnectionEvent(DisconnectionEvent arg0) {			
	}	

	@Override
	public void onStatusEvent(StatusEvent arg0) {		
	}

	
	@Override
	public String toString(){
		return Integer.toString(wiimote.getWiimoteId());
	}

	
	
	
}


